#include "uart/uart.h"

#define DEBUG_ON 1
#include "rtt_debug.h"

#include "ring_fifo.h"

#include "uart/uart1.h"

#define SEND_BY_POLL    0
#define SEND_BY_IT      1
#define SEND_BY_DMA     2

struct uart_rt_t {
    struct ring_fifo_t *rx_fifo;
    uint8_t rx_fifo_buf[8192];
    struct ring_fifo_t *tx_fifo;
    uint8_t tx_fifo_buf[4096];
    uint32_t head_ptr;
    volatile uint32_t tc_flag;
    uint32_t send_type;
};

#define UART1_SEND_TYPE SEND_BY_DMA
static struct uart_rt_t uart1_rt;

static inline void uart1_write_rx_fifo(const void *data, uint32_t len)
{
    uint32_t copied;
    if((NULL == data) || (0 == len)) { return ; }
    
    copied = ring_fifo_write(uart1_rt.rx_fifo, data, len);
    if(copied != len)
    {
        PRINTF("uart1_rt.rx_fifo is full.\n");
    }
}

uint32_t uart1_read(void *buf, uint32_t len)
{
    if((NULL == buf) || (0 == len)) { return 0; }
    
    return ring_fifo_read(uart1_rt.rx_fifo, buf, len);
}

void uart1_write(const void *data, uint32_t len)
{
    uint32_t copied;
    if((NULL == data) || (0 == len)) { return ; }
    
    copied = ring_fifo_write(uart1_rt.tx_fifo, data, len);
    if(copied != len)
    {
        PRINTF("uart1_rt.tx_fifo is full.\n");
    }
}

static inline uint32_t uart1_read_tx_fifo(void *buf, uint32_t len)
{
    if((NULL == buf) || (0 == len)) { return 0; }
    
    return ring_fifo_read(uart1_rt.tx_fifo, buf, len);
}

void uart1_poll_send(void)
{
    uint32_t len;
    /* Notice static */
    static uint8_t buf[256];
    UART_HandleTypeDef *huart;
    
    huart = Uart1GetHandle();
    if(0 != uart1_rt.tc_flag)
    {
        len = uart1_read_tx_fifo(buf, sizeof(buf));
        if(len > 0)
        {
            switch(uart1_rt.send_type)
            {
                case SEND_BY_POLL:
                    HAL_UART_Transmit(huart, buf, len, 0xffff);
                    break;
                case SEND_BY_IT:
                    uart1_rt.tc_flag = 0;
                    HAL_UART_Transmit_IT(huart, buf, len);
                    break;
                case SEND_BY_DMA:
                    if(NULL == huart->hdmatx)
                    {
                        PRINTF("uart1 not enable dma tx.\n");
                        for(;;);
                    }
                    uart1_rt.tc_flag = 0;
                    HAL_UART_Transmit_DMA(huart, buf, len);
                    break;
            }
        }
    }
}

static inline void uart2_write_rx_fifo(const void *data, uint32_t len)
{
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if((huart->Instance) == USART1)
    {
        uart1_rt.tc_flag = 1;
    }
    else if((huart->Instance) == USART2)
    {
    }
}

void HAL_UART1_RxIdleCallback(UART_HandleTypeDef *huart)
{
    uint32_t tail_ptr;
    uint32_t copy, offset;
    
    /*
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     * |     head_ptr          tail_ptr         |
     * |         |                 |            |
     * |         v                 v            |
     * | --------*******************----------- |
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     */
    
    /* 已接收 */
    tail_ptr = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
    
    offset = uart1_rt.head_ptr % huart->RxXferSize;
    copy = tail_ptr - offset;
    uart1_rt.head_ptr += copy;
    
    uart1_write_rx_fifo(huart->pRxBuffPtr + offset, copy);
}

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
    uint32_t tail_ptr;
    uint32_t offset, copy;
    
    /* 当接收buf大小为1时忽略半满中断 */
    if(1 == huart->RxXferSize) { return ; }
    
    /*
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     * |                  half                  |
     * |     head_ptr   tail_ptr                |
     * |         |          |                   |
     * |         v          v                   |
     * | --------*******************----------- |
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     */
    
    if((huart->Instance) == USART1)
    {
        tail_ptr = (huart->RxXferSize >> 1) + (huart->RxXferSize & 1);
        
        offset = uart1_rt.head_ptr % huart->RxXferSize;
        copy = tail_ptr - offset;
        uart1_rt.head_ptr += copy;
        
        uart1_write_rx_fifo(huart->pRxBuffPtr + offset, copy);
    }
    else if((huart->Instance) == USART2)
    {
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    uint32_t tail_ptr;
    uint32_t offset, copy;
    
    if(NULL == huart->hdmarx)
    {
        /* 如果为中断模式，恢复接收地址指针到初始化buffer位置 */
        huart->pRxBuffPtr -= huart->RxXferSize;
    }
    
    /*
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     * |                  half                  |
     * |                    | head_ptr tail_ptr |
     * |                    |    |            | |
     * |                    v    v            v |
     * | ------------------------************** |
     * +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
     */

    if((huart->Instance) == USART1)
    {
        tail_ptr = huart->RxXferSize;
        
        offset = uart1_rt.head_ptr % huart->RxXferSize;
        copy = tail_ptr - offset;
        uart1_rt.head_ptr += copy;
        
        uart1_write_rx_fifo(huart->pRxBuffPtr + offset, copy);
    }
    else if((huart->Instance) == USART2)
    {
    }
  
    if(NULL != huart->hdmarx)
    {
        if(huart->hdmarx->Init.Mode != DMA_CIRCULAR)
        {
            while(HAL_OK != HAL_UART_Receive_DMA(huart, huart->pRxBuffPtr, huart->RxXferSize))
            {
                __HAL_UNLOCK(huart);
            }
        }
    }
    else
    {
        while(HAL_UART_Receive_IT(huart, huart->pRxBuffPtr, huart->RxXferSize))
        {
            __HAL_UNLOCK(huart);
        }
    }
}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        uart1_rt.rx_fifo = ring_fifo_init(uart1_rt.rx_fifo_buf, sizeof(uart1_rt.rx_fifo_buf) / sizeof(uart1_rt.rx_fifo_buf[0]), RF_TYPE_STREAM);
        if(NULL == uart1_rt.rx_fifo)
        {
            PRINTF("uart1 rx fifo init failed.\n");
            for(;;);
        }
        uart1_rt.tx_fifo = ring_fifo_init(uart1_rt.tx_fifo_buf, sizeof(uart1_rt.tx_fifo_buf) / sizeof(uart1_rt.tx_fifo_buf[0]), RF_TYPE_STREAM);
        if(NULL == uart1_rt.tx_fifo)
        {
            PRINTF("uart1 tx fifo init failed.\n");
            for(;;);
        }
        
        uart1_rt.head_ptr = 0;
        uart1_rt.tc_flag = 1;
        uart1_rt.send_type = UART1_SEND_TYPE;
        
        Uart1RegisterIdleIrqCallback(HAL_UART1_RxIdleCallback);
        
        HAL_UART_1_MspInit(huart);
    }
    else if(huart->Instance == USART2)
    {
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    __IO uint32_t tmpErr = 0x00U;
    
    tmpErr = HAL_UART_GetError(huart);
    if(HAL_UART_ERROR_NONE == tmpErr)
    {
        return ;
    }
    
    switch(tmpErr)
    {
        case HAL_UART_ERROR_PE:
            __HAL_UART_CLEAR_PEFLAG(huart);
            break;
        case HAL_UART_ERROR_NE:
            __HAL_UART_CLEAR_NEFLAG(huart);
            break;
        case HAL_UART_ERROR_FE:
            __HAL_UART_CLEAR_FEFLAG(huart);
            break;
        case HAL_UART_ERROR_ORE:
            __HAL_UART_CLEAR_OREFLAG(huart);
            break;
        case HAL_UART_ERROR_DMA:
            
            break;
        default:
            break;
    }
    
    if(NULL != huart->hdmarx)
    {
        while(HAL_UART_Receive_DMA(huart, huart->pRxBuffPtr, huart->RxXferSize))
        {
          __HAL_UNLOCK(huart);
        }
    }
    else
    {
        /* 恢复接收地址指针到初始 buffer 位置 ，初始地址 = 当前地址 - 已接收的数据个数，已接收的数据个数 = 需要接收数 - 还未接收数*/
        while(HAL_UART_Receive_IT(huart, huart->pRxBuffPtr - (huart->RxXferSize - huart->RxXferCount), huart->RxXferSize))
        {
          __HAL_UNLOCK(huart);
        }
    }
}
